package com.zilue.security.util.rsa;

import com.zilue.security.util.base64.Base64Util;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by zilue on 2017/1/10.
 */
public class RSAUtil {

    /**
     * 加密算法RSA
     */
    public static final String KEY_ALGORITHM = "RSA";

    /**
     * 签名算法
     */
    public static final String SIGNATURE_ALGORITHM  = "SHA1withRSA";

    /**
     * 获取公钥的key
     */
    public static final String PUBLIC_KEY = "RSAPublicKey";

    /**
     * 获取私钥的key
     */
    public static final String PRIVATE_KEY = "RSAPrivateKey";


    /**
     * <p>
     * 生成密钥对(公钥和私钥)
     * </p>
     *
     * @return
     * @throws Exception
     */
    public static Map<String, Object> genKeyPair() throws Exception {
        KeyPairGenerator rsa = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        rsa.initialize(2048);
        rsa.generateKeyPair();
        KeyPair keyPair = rsa.genKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 私钥签名
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        byte[] pk = Base64Util.decodeByte(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(pk);
        PrivateKey privateKeyPK = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateKeyPK);
        signature.update(data);
        return Base64Util.encodeByte(signature.sign());
    }

    /**
     * 公钥验签
     * @param data
     * @param publicKey
     * @param sign
     * @return
     * @throws Exception
     */
    public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
        byte[] pk = Base64Util.decodeByte(publicKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pk);
        PublicKey publicKeyPK = keyFactory.generatePublic(x509KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicKeyPK);
        signature.update(data);
        return signature.verify(Base64Util.decodeByte(sign));
    }



    /**
     * 私钥加密
     *
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(String data, String privateKey) throws Exception {
        byte[] pk = Base64Util.decodeByte(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(pk);
        PrivateKey privateKeyPK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(privateKeyPK.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKeyPK);
        return cipher.doFinal(data.getBytes());
    }

    /**
     * 私钥解密
     *
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data, String privateKey) throws Exception {
        byte[] pk = Base64Util.decodeByte(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(pk);
        PrivateKey privateKeyPK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(privateKeyPK.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKeyPK);
        return cipher.doFinal(data);
    }


    /**
     * 公钥加密
     *
     * @param data
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(String data, String publicKey) throws Exception {
        byte[] pk = Base64Util.decodeByte(publicKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pk);
        PublicKey publicKeyPK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(publicKeyPK.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKeyPK);
        return cipher.doFinal(data.getBytes());
    }


    /**
     * 公钥解密
     *
     * @param data
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, String publicKey) throws Exception {
        byte[] pk = Base64Util.decodeByte(publicKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pk);
        PublicKey publicKeyPK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(publicKeyPK.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKeyPK);
        return cipher.doFinal(data);
    }


    public static void main(String[] args) throws Exception {
        Map<String, Object> map = RSAUtil.genKeyPair();
        PublicKey publicKey = (PublicKey) map.get(PUBLIC_KEY);
        PrivateKey private_key = (PrivateKey) map.get(PRIVATE_KEY);
        System.out.println(publicKey.getFormat());
        System.out.println(publicKey.getAlgorithm());
        String pubilcKeyStr = Base64Util.encodeByte(publicKey.getEncoded());
        System.out.println("公钥：" + pubilcKeyStr);

        System.out.println(private_key.getFormat());
        System.out.println(private_key.getAlgorithm());
        String privateKeyStr = Base64Util.encodeByte(private_key.getEncoded());
        System.out.println("私钥：" + privateKeyStr);

        pubilcKeyStr = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArRmZcXXPRIzVfYG5vwLItoWy3FVWR1RK\n" +
                "u3rMA3g75bC2sgr2JfvWyWQoS5LjbLRdC7qKoPDPZEm6fpbYv40SAcFwn2BesmloppCvnscZf2D3\n" +
                "dV43T8oWUQNFD2CJo5x2rkmrZks54rSRoKI7JvHRmi7VH5r/DHu/fWzRgCMvEtECLQzo1SMOJ0NV\n" +
                "BaXQVLrNOL93Hq79wgerVbPy4zNcH+Sb2ermQOW3X2ZFu/LaP23aTPAyB3MbEJVWJMPA1sx+FYJW\n" +
                "bEr/GNqOUzKO9PnQFBPQ5YpDFoQ+foRLoyjbM1nZ34YngbaLVLSppaJ49VdWtKrSB7eub8yipXPB\n" +
                "TkTXDQIDAQAB";
        privateKeyStr = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtGZlxdc9EjNV9gbm/Asi2hbLc\n" +
                "VVZHVEq7eswDeDvlsLayCvYl+9bJZChLkuNstF0Luoqg8M9kSbp+lti/jRIBwXCfYF6yaWimkK+e\n" +
                "xxl/YPd1XjdPyhZRA0UPYImjnHauSatmSznitJGgojsm8dGaLtUfmv8Me799bNGAIy8S0QItDOjV\n" +
                "Iw4nQ1UFpdBUus04v3cerv3CB6tVs/LjM1wf5JvZ6uZA5bdfZkW78to/bdpM8DIHcxsQlVYkw8DW\n" +
                "zH4VglZsSv8Y2o5TMo70+dAUE9DlikMWhD5+hEujKNszWdnfhieBtotUtKmlonj1V1a0qtIHt65v\n" +
                "zKKlc8FORNcNAgMBAAECggEAcFqPWC+pissGv2H2WF7MPHxnbdAOIlo575py1UWzSxD6ZHHs9xaR\n" +
                "gUJ7TSJYb3RaeIRp+rCTTHr2i7gJk7tTFsSh/zCkBpWYkZSUCTEeAanEtO+kYyu+dHL03lhAvmuO\n" +
                "NO4oTEtDlTyy0Vq7njmTXMpNFyiZp1ajIhwBl3Q+16y0lo6Yne2oBggv8v4KYaSiT6PYaWHLFmzy\n" +
                "zYPbLWFXsoSVHHrKe5AXCSRw3p2U4K33pe8pIxPXiB3n+hWvY+gZy+HHCCLC1zISWF5+Q/LO2Er8\n" +
                "IK4FThoA6yrn0paBdexK+gtsJAdeMIFbC1z5k9veKXFHHlQQ1ZgJGX91DC+8WQKBgQDZ+6I+cE/U\n" +
                "gXj8C9ZACgP383m0aWyKLd/LxVvpd7sMmUVcucIDNJz7/fGSCWRJSmZ8Ot8RniLjXxe57XdVQhg5\n" +
                "X75XriapvVC0+zzwz8al7yWUEErP9TCt/dMpqUSeahD+Tbos0a+qdYhq9JgBix9nqOXOY/AXMsIa\n" +
                "h5bBJJOAlwKBgQDLSg9Tvcu2/tiAmrAg7AGpu9EqJxLVQ5WmIskaAqqzPEKX6Tbwg7Rt3Ali4SJ4\n" +
                "p392soq/N4NnfV1miMALR+po0asWJE6oweCraRHsXdYSNaBAfnov28wBa5G8cOR3QYptD+9N/n6T\n" +
                "/BMgupj7i1uVzQ1DxYKguZ+lLNIwUn21+wKBgCbMjD9S3FK1zOQH81WosrYihyoejaw2qBvsAAUZ\n" +
                "Q5jlexwbEDZj2gFcXPAibdBBxuYb0HKhVBJmbaGxa8koH4muygFvRQB3avMbuOggA3qri2PEVpyX\n" +
                "RtfhUwGaWFVeCbJKAXZSyFKt4t8utBOqQKfBv02yKhzm8ven5KRyLzL3AoGBAIyFty6VxdnLM/FB\n" +
                "/HnlagjgMWfH9rbArxNWfFike0bGYuoLZdS/1dsS/NIC+gcZEX0FUe93+jdxazzTTpz9q0WlmXQG\n" +
                "yPDSg/E5AhC3lKClvQ6X3vJyJwTcTLNL/kGJZpyZJTxurSSyXK6FDfbjj/1u7rpoLzHW3koZP3nz\n" +
                "q749AoGBAK3CnD6yk8bNeZ+VbRPNz4u0RSoQik5u+4yBq0/PX9nTf2Sj/h8WCCT28wKLUBjgp+x3\n" +
                "6l2fvEz62bPaUCgOglva8zADp1YCxlw8q3vGqSDv+ToCbzksbv4AfxIVB4l/005Hj0qtxZk+OgFa\n" +
                "LDoCst9YU90PwQV2FvTo4wNzOWKm";
        String str = "你哈啊";
        System.out.println("私钥加密前：" + str);
        byte[] privateStr = RSAUtil.encryptByPrivateKey(str, privateKeyStr);
        System.out.println("私钥加密后：" + privateStr);

        byte[] privateStrAfter = RSAUtil.decryptByPublicKey(privateStr, pubilcKeyStr);
        System.out.println("公钥解密后：" + new String(privateStrAfter));

        byte[] publicStr = RSAUtil.encryptByPublicKey(str, pubilcKeyStr);
        System.out.println("公钥加密后：" + publicStr);
        byte[] publicStrAfter = RSAUtil.decryptByPrivateKey(publicStr, privateKeyStr);
        System.out.println("私钥解密后：" + new String(publicStrAfter));

        String sign = RSAUtil.sign(str.getBytes(), privateKeyStr);
        System.out.println("签名：" + sign);
        boolean verify = RSAUtil.verify(str.getBytes(), pubilcKeyStr, sign);
        System.out.println("验签：" + verify);

    }
    
}
